﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;

namespace CommonUtils
{
    public static class IpUtil
    {
        public static string MyIp
        {
            get
            {
                StringBuilder Info = new StringBuilder("");

                Info.Append("本机名：");
                Info.AppendLine(Dns.GetHostName());

                Info.Append("IP 地址：");
                Info.AppendLine(" -> ");
                IPAddress[] ipHost = Dns.GetHostAddresses(Dns.GetHostName());
                foreach (IPAddress address in ipHost)
                {
                    long scopeId = 0;
                    try
                    {
                        scopeId = address.ScopeId;
                    }
                    catch
                    {
                    }
                    Info.AppendLine(scopeId + " >> ");
                    Info.AppendLine(address.ToString());
                    Info.AppendLine();
                }

                return Info.ToString();
            }
        }

        public static string Hide(string ip)
        {
            var cells = ip.Split('.');
            if (cells.Length == 4)
                return string.Format("{0}.{1}.*.{2}", cells[0], cells[1], cells[3]);
            return ip;
        }

        //public static string GetZone(string ip)
        //{
        //}

        public static IPAddress GetFromIpString(string ip)
        => IPAddress.Parse(ip);

        public static IPAddress GetFromIpParts(byte part1, byte part2, byte part3, byte part4)
        => new IPAddress(new byte[] { part1, part2, part3, part4 });

        public static IPAddress GetFromDomainName(string domainName)
        => Dns.GetHostAddresses(domainName).FirstOrDefault();

        public static IPAddress GetFromHost(string ipOrDomainName)
        => GetFromDomainName(ipOrDomainName);

        public static byte[] ToParts(this IPAddress ip)
        => ip.GetAddressBytes();

        public static IPAddress GetNext(this IPAddress ip)
        {
            var bytes = ip.GetAddressBytes();
            bytes[3]++;
            if (bytes[3] == 0)
            {
                bytes[2]++;
                if (bytes[2] == 0)
                {
                    bytes[1]++;
                    if (bytes[1] == 0)
                    {
                        bytes[0]++;
                    }
                }
            }
            return new IPAddress(bytes);
        }

        /// <summary>
        /// 获取EndPoint
        /// </summary>
        public static IPEndPoint GetEndPoint(string hostPort)
        {
            var cells = hostPort.Split(':', ',', ' ');
            var ip = GetFromHost(cells[0]);
            return new IPEndPoint(ip, int.Parse(cells[1]));
        }

        /// <summary>
        /// 获取EndPoint
        /// </summary>
        public static IPEndPoint GetEndPoint(string ipOrDomain, int port)
        => new IPEndPoint(GetFromHost(ipOrDomain), port);

        static Ping ping = new Ping();

        public static bool CanPing(string host, double timeoutSeconds = 0.2)
        {
            var milliseconds = (int)(timeoutSeconds * 1000);
            var reply = ping.Send(host, milliseconds);
            LogUtil.log("ping {0} limit {1} ms, result: {2}", host, milliseconds, reply.Status);
            return reply.Status == IPStatus.Success;
        }

        public static void PrintPingStatus(string ipOrDomain)
        {
            var ip = GetFromHost(ipOrDomain);
            if (ip == null)
                return;

            var ping = new Ping();
            var reply = ping.Send(ip);
            LogUtil.PrintInfo("来自 {0} [{1}] [{2}] 的回复: 结果={3} 字节={4} 时间={5}ms TTL={6}", ipOrDomain, ip, reply.Address, reply.Status, reply.Buffer.Length, reply.RoundtripTime, reply.Options == null ? 0 : reply.Options.Ttl);
        }

        public static void Ping(string ipOrDomain) => PrintPingStatus(ipOrDomain);

        public static void PingTest()
        {
            Ping("localhost");
            Ping("127.0.0.1");
            Ping("baidu.com");
            Ping("jd.com");

            for (int index = 0; index < 20; index++)
                PrintPingStatus("v" + index + ".oculusss.pro");
        }

        private static Map<string, string[]> _countryIpsMap;

        private static Map<string, string[]> CountryIpsMap
        {
            get
            {
                if (_countryIpsMap == null)
                {
                    _countryIpsMap = new Map<string, string[]>();
                    //注释了部分大IP段
                    var lines = ResourceUtil.GetFromCommon(ResourceName.IpDivisionTxt).ReadLines();
                    string key = null;
                    var ips = new List<string>();
                    foreach (var line in lines)
                    {
                        var cells = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                        if (cells.Length == 1)
                        {
                            if (ips.Count > 0)
                                _countryIpsMap[key] = ips.ToArray();
                            ips = new List<string>();
                            key = cells[0];
                        }
                        if (cells.Length > 2 && cells[0][0] != '#')
                        {
                            var ip = GetFromIpString(cells[0]);
                            var endIp = GetFromIpString(cells[2]);
                            LogUtil.PrintInfo("add new ip division of {0},from {1} to {2}.", key, ip, endIp);
                            while (ip.Address != endIp.Address)
                            {
                                ips.Add(ip.ToString());
                                ip = ip.GetNext();
                            }
                            ips.Add(endIp.ToString());
                        }
                    }
                }
                return _countryIpsMap;
            }
        }

        public static void PrinDivision()
        {
            var sb = new StringBuilder();
            foreach (var pair in CountryIpsMap)
                sb.AppendLine("{0} {1}", pair.Key, pair.Value.Length);
            sb.Print();
        }

        public static string[] GetFromCountry(string country)
        {
            foreach (var pair in CountryIpsMap)
                if (pair.Key.Contains(country))
                    return pair.Value;
            return default;
        }
    }
}
